﻿using DocumentFormat.OpenXml.Spreadsheet;
using Magicodes.ExporterAndImporter.Pdf;
using MiniSoftware;
using NPOI.OpenXmlFormats.Wordprocessing;
using NPOI.XWPF.UserModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace NP.BPMReportPlatform.WordHelper
{
    public static class MiniWordHelper
    {
        /// <summary>
        /// 通过模板生产word文档
        /// </summary>
        /// <param name="template">模板类型</param>
        /// <param name="dics">模板数据值</param>
        /// <returns>流数据</returns>
        /// <exception cref="Exception"></exception>
        public static MemoryStream CreateWord(WordTemplateEnum template, Dictionary<string, object> dics)
        {
            string url = Environment.CurrentDirectory + "/wwwroot/docs/wordTemplate/" + template.ToString() + ".docx";
            if (!File.Exists(url))
            {
                throw new Exception("未找到正确word模板！");
            }
            byte[] bytes = File.ReadAllBytes(url);

            MemoryStream memoryStream = new MemoryStream();
            MiniWord.SaveAsByTemplate(memoryStream, bytes, dics);
            memoryStream.Seek(0, SeekOrigin.Begin);
            return memoryStream;
        }

        /// <summary>
        /// 生成PDF
        /// </summary>
        /// <param name="template"></param>
        /// <param name="dics"></param>
        /// <returns></returns>
        public static byte[] CreatePdf(WordTemplateEnum template, Dictionary<string, object> dics)
        {
            var memory = CreateWord(template, dics);
            return WordToPdf2(memory);
            // return WordToPdf(memory);
        }

        /// <summary>
        /// word文档转成pdf文档
        /// Aspose方案，收费，需要破解，破解后Linux服务器上不行
        /// </summary>
        /// <param name="aDocument">word流</param>
        /// <returns></returns>
        private static byte[] WordToPdf(MemoryStream aDocument)
        {
            Aspose.Words.Document doc = new Aspose.Words.Document(aDocument);
            using (MemoryStream firstStream = new MemoryStream())
            {
                doc.Save(firstStream, Aspose.Words.SaveFormat.Pdf);
                aDocument.Close();
                return firstStream.ToArray();
            }
        }

        /// <summary>
        /// word文档转成pdf文档
        /// word -> Html -> pdf
        /// </summary>
        /// <param name="aDocument">word流</param>
        /// <returns></returns>
        private static byte[] WordToPdf2(MemoryStream aDocument)
        {
            string htmlstr = WordToHTML(aDocument);
            var exporter = new PdfExporter();

            // 此处使用默认模板导出
            var pdfAtt = new PdfExporterAttribute()
            {
                IsEnablePagesCount = true,
                Orientation = DinkToPdf.Orientation.Portrait,
                PaperKind = DinkToPdf.PaperKind.A4,
                FooterSettings = new DinkToPdf.FooterSettings() { Center = "第[page]页 共[toPage]页" }
            };

            return exporter.ExportBytesByTemplate(new { }, pdfAtt, htmlstr).Result;
        }

        /// <summary>
        /// word文档转成pdf文档
        /// </summary>
        /// <param name="aDocument">word流</param>
        /// <returns></returns>
        public static string WordToHTML(MemoryStream aDocument)
        {
            return NpoiDoc(aDocument);

            //using (MemoryStream firstStream = new MemoryStream())
            //{
            //    doc.Save(firstStream, Aspose.Words.SaveFormat.Pdf);
            //    aDocument.Close();
            //    return firstStream.ToArray();
            //}
        }

        #region word 转html
        /// <summary>
        ///     Npoi处理Doc
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="isImgUploadAliYun"></param>
        /// <returns></returns>
        public static string NpoiDoc(Stream stream, bool isImgUploadAliYun = false)
        {
            var myDocx = new XWPFDocument(stream); //打开07（.docx）以上的版本的文档


            var picInfoList = PicturesHandleAsync(myDocx, isImgUploadAliYun);

            var sb = new StringBuilder();

            foreach (var para in myDocx.BodyElements)
                switch (para.ElementType)
                {
                    case BodyElementType.PARAGRAPH:
                        {
                            var paragraph = (XWPFParagraph)para;
                            sb.Append(ParaGraphHandle(paragraph, picInfoList));

                            break;
                        }

                    case BodyElementType.TABLE:
                        var paraTable = (XWPFTable)para;
                        sb.Append(TableHandle(paraTable, picInfoList));
                        break;
                }


            return sb.Replace(" style=''", "").ToString();
        }

        /// <summary>
        ///     图片处理
        /// </summary>
        /// <param name="myDocx"></param>
        /// <param name="isImgUploadAliYun">图片是否上传阿里云</param>
        /// <returns></returns>
        public static List<PicInfo> PicturesHandleAsync(XWPFDocument myDocx, bool isImgUploadAliYun = false)
        {
            var picInfoList = new List<PicInfo>();
            var picturesList = myDocx.AllPictures;
            foreach (var pictures in picturesList)
            {
                var pData = pictures.Data;
                var picPackagePart = pictures.GetPackagePart();
                var picPackageRelationship = pictures.GetPackageRelationship();
                var picInfo = new PicInfo
                {
                    Id = picPackageRelationship.Id,
                    PicType = picPackagePart.ContentType
                };

                try
                {
                    //if (isImgUploadAliYun)
                    //{
                    //    //阿里云上传图片方法
                    //    var url = await _binaryObjectManager.SaveAsync(new BinaryObject
                    //    { Bytes = pData, FileName = pictures.FileName, FileType = picInfo.PicType });
                    //    picInfo.Url = url;
                    //}
                }
                catch (Exception)
                {
                    // ignored
                }

                if (string.IsNullOrWhiteSpace(picInfo.Url))
                    picInfo.Url = $"data:{picInfo.PicType};base64,{Convert.ToBase64String(pData)}";
                //先把pData传阿里云得到url  如果有其他方式传改这里 或者转base64

                picInfoList.Add(picInfo);
            }

            return picInfoList;
        }

        /// <summary>
        ///     word中的表格处理
        /// </summary>
        /// <param name="paraTable"></param>
        /// <param name="picInfoList"></param>
        /// <returns></returns>
        public static StringBuilder TableHandle(XWPFTable paraTable, List<PicInfo> picInfoList)
        {
            var sb = new StringBuilder();

            var rows = paraTable.Rows;
            sb.Append("<table border='1' cellspacing='0'>");
            foreach (var row in rows)
            {
                var cells = row.GetTableCells();

                sb.Append(
                    "<tr style='");
                //var firstRowCell = cells[0];


                sb.Append(
                    "'>");


                foreach (var cell in cells)
                {
                    var cellCtTc = cell.GetCTTc();
                    var tcPr = cellCtTc.tcPr;


                    sb.Append("<td style='");

                    if (!string.IsNullOrWhiteSpace(tcPr.tcW?.w))
                        sb.Append($"width:{tcPr.tcW.w}px;");
                    if (!string.IsNullOrWhiteSpace(tcPr.shd?.fill))
                        sb.Append($"background-color: #{tcPr.shd.fill};");

                    sb.Append("'>");
                    var cellParagraphs = cell.Paragraphs;
                    foreach (var cellParagraph in cellParagraphs)
                        sb.Append(ParaGraphHandle(cellParagraph, picInfoList));

                    //sb.Append(cell.GetText());
                    sb.Append("</td>");
                }


                sb.Append("</tr>");
            }

            sb.Append("</table>");
            return sb;
        }

        /// <summary>
        ///     word文本对应处理
        /// </summary>
        /// <param name="ctr"></param>
        /// <returns></returns>
        public static StringBuilder FontHandle(CT_R ctr)
        {
            var sb = new StringBuilder();

            #region 文本格式

            var textList = ctr.GetTList();
            foreach (var text in textList)
            {
                sb.Append(
                    "<span style='");
                if (!string.IsNullOrWhiteSpace(ctr.rPr?.color?.val))
                    sb.Append(
                        $"color:#{ctr.rPr.color.val};");
                if (!string.IsNullOrWhiteSpace(ctr.rPr?.highlight?.val.ToString()))
                    sb.Append(
                        $"background-color: {ctr.rPr.highlight.val};");
                if (ctr.rPr?.i?.val == true)
                    sb.Append(
                        "font-style:italic;");
                if (ctr.rPr?.b?.val == true)
                    sb.Append(
                        "font-weight:bold;");
                if (ctr.rPr?.sz != null)
                    sb.Append(
                        $"font-size:{ctr.rPr.sz.val}px;");
                if (!string.IsNullOrWhiteSpace(ctr.rPr?.rFonts?.ascii))
                    sb.Append(
                        $"font-family:{ctr.rPr.rFonts.ascii};");

                sb.Append(
                    "'>");

                sb.Append(text.Value);
                sb.Append("</span>");
            }

            #endregion

            return sb;
        }

        /// <summary>
        ///     word图片对应处理
        /// </summary>
        /// <param name="ctr"></param>
        /// <param name="picInfoList"></param>
        /// <returns></returns>
        public static StringBuilder DrawingHandle(CT_R ctr, List<PicInfo> picInfoList)
        {
            var sb = new StringBuilder();
            var drawingList = ctr.GetDrawingList();
            foreach (var drawing in drawingList)
            {
                var a = drawing.GetInlineList();
                foreach (var a1 in a)
                {
                    var anyList = a1.graphic.graphicData.Any;

                    foreach (var any1 in anyList)
                    {
                        var pictures = picInfoList
                            .FirstOrDefault(x =>
                                any1.IndexOf("a:blip r:embed=\"" + x.Id + "\"", StringComparison.Ordinal) > -1);
                        if (pictures != null && !string.IsNullOrWhiteSpace(pictures.Url))
                            sb.Append($@"<img src='{pictures.Url}' />");
                    }
                }
            }

            return sb;
        }

        /// <summary>
        ///     word行处理为P标签
        /// </summary>
        /// <param name="paragraph"></param>
        /// <returns></returns>
        public static StringBuilder TagPHandle(XWPFParagraph paragraph)
        {
            var sb = new StringBuilder();
            sb.Append("<p style='");

            try
            {
                //左右对齐

                var fontAlignment = paragraph.FontAlignment;
                string fontAlignmentName;
                switch (fontAlignment)
                {
                    case 0:
                        fontAlignmentName = "auto";
                        break;
                    case 1:
                        fontAlignmentName = "left";
                        break;
                    case 2:
                        fontAlignmentName = "center";
                        break;
                    case 3:
                        fontAlignmentName = "right";
                        break;
                    default:
                        fontAlignmentName = "auto";
                        break;
                }
                //自动和左对齐不需样式
                if (fontAlignment > 1) sb.Append($"text-align:{fontAlignmentName};");


                var em = paragraph.IndentationFirstLine / 240;

                if (em > 0) sb.Append($"text-indent:{em}em;");
                if (paragraph.Runs.Count() == 0) sb.Append($"padding-bottom:2em;");
                if (paragraph.SpacingLineRule == LineSpacingRule.EXACT)
                {
                    sb.Append($"line-height:3em;");
                }
            }
            catch (Exception)
            {
                // ignored
            }

            sb.Append("'>");
            return sb;
        }

        /// <summary>
        ///     word文档对应行内容处理
        /// </summary>
        /// <param name="paragraph"></param>
        /// <param name="picInfoList"></param>
        /// <returns></returns>
        public static StringBuilder ParaGraphHandle(XWPFParagraph paragraph, List<PicInfo> picInfoList)
        {
            var sb = new StringBuilder();

            #region P标签
            sb.Append(TagPHandle(paragraph));
            #endregion
            var runs = paragraph.Runs;
            foreach (var run in runs)
            {
                var ctr = run.GetCTR();

                #region 图片格式

                sb.Append(DrawingHandle(ctr, picInfoList));

                #endregion

                #region 文本格式
                if (ctr.GetTList().Count() > 0 && ctr.GetTList().First()?.Value == "[[[分页符]]]")
                {
                    sb = new StringBuilder().Append($"<div style=\"page-break-after: always; clear:both;\"></div>");
                    return sb;
                }
                else
                {
                    sb.Append(FontHandle(ctr));
                }

                #endregion
            }

            sb.Append("</p>");
            return sb;
        }

        #endregion
    }

    public class PicInfo
    {
        /// <summary>
        ///     图片编号
        /// </summary>
        public string Id { get; set; }

        /// <summary>
        ///     图片类型
        /// </summary>
        public string PicType { get; set; }

        /// <summary>
        ///     上传地址/或者Base64
        /// </summary>
        public string Url { get; set; }
    }
}
